package com.haixiaoke.saas.repository.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.haixiaoke.saas.repository.core.AjaxResult;
import com.haixiaoke.saas.repository.exception.BizException;
import com.haixiaoke.saas.repository.pojo.Order;
import com.haixiaoke.saas.repository.service.IAppUserService;
import com.haixiaoke.saas.repository.service.IOrderService;
import com.haixiaoke.saas.repository.service.ISubscribeService;
import com.haixiaoke.saas.repository.util.GsonUtil;
import com.haixiaoke.saas.repository.util.Template;
import com.haixiaoke.saas.repository.vo.SubscribeVo;
import com.mzj.saas.commons.StatusCode;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpInMemoryConfigStorage;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateData;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.*;


/**
 * 订阅消息service
 *
 * @author qixi
 * @date 2023-05-05
 */
@Slf4j
@Service
public class SubscribeServiceImpl implements ISubscribeService {

    @Autowired
    private IOrderService orderService;

    @Autowired
    private IAppUserService appUserService;


    /**
     * 嗨小克长短租小程序appId
     */
    private static final String NEW_APP_ID = "wxe627e86e6103a634";

    /**
     * 嗨小克长短租小程序密钥
     */
    private static final String NEW_SECRET_KEY = "ac66e04c9013a03fdd4f46bb2d54297c";

    /**
     * 嗨小克小程序appId
     */
    private static final String APP_ID = "wx8e37f936ae1c6a70";

    /**
     * 嗨小克程序密钥
     */
    private static final String SECRET_KEY = "38f48028a5cf5090d396623cc573e92e";


    /**
     * 嗨小克程序模板id
     */
    private static final String TEMPLATE_ID = "an7lhXkjWPouXkagGz_KV4lGLKbuh3wQbNe98MC9PPg";

    /**
     * 嗨小克长短租模板id
     */
    private static final String NEW_TEMPLATE_ID = "W-N64cED-PExkxIrrz9WZMenqXTqbS2i_opJ7f_hf1E";


    /**
     * 嗨小克程序模板id
     */
    private static final String ORDER_STATUS_TEMPLATE_ID = "62VVrDFUK9fDP5NYJwCyJ8qGFd3nT17z6w_wPMrw2LM";

    /**
     * 嗨小克长短租房屋动态变动模板id
     */
    private static final String HOUSE_STATE_TEMPLATE_ID = "d1tr1E3mZ8sfoPLX_nBwXZt3nq-zukJ2IJkoixvmw2k";


    /**
     * 订阅消息 accessToken url
     */
    private static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token";

    /**
     * 订阅消息 url
     */
    private static final String SUBSCRIBE_URL = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send";


    private static final String RP_BILL_MSG_TEMPLATEID = "hgd93qN0WAzUbQ1mbtdJZ8-E6Wokc2l7C29-CDENekU";

    private static final String RP_DEDUCTION_BALANCE_MSG_TEMPLATEID = "p2d8OHHx3rkoSs63OCzYMru5SXK5Bh5loSGMSwhCUBg";


    @Value("${officialAccount.appId}")
    private String officialAccountAppId;

    @Value("${officialAccount.secret}")
    private String officialAccountSecret;

    @Override
    public AjaxResult send(SubscribeVo subscribeVo) {
        Template template = new Template();
        String openId = subscribeVo.getOpenId();
        Integer flag = subscribeVo.getFlag();
        if (1 == flag) {
            template.setTemplateId(TEMPLATE_ID);
        } else {
            template.setTemplateId(NEW_TEMPLATE_ID);
        }
        template.setToUser(openId);

        template.setPage("pages/index/index");
        Map<String, Object> map = new LinkedHashMap<>();

        // 项目名称
        // {{thing7.DATA}}
        // 应缴金额
        // {{amount4.DATA}}
        // 缴费类型
        // {{thing6.DATA}}
        // 最晚支付日期
        // {{time5.DATA}}
        // 账单周期
        // {{time3.DATA}}
        map.put("time3", subscribeVo.getBillStartTime() + "~" + subscribeVo.getBillEndTime());
        map.put("time5", subscribeVo.getLastPaymentTime());
        map.put("amount4", subscribeVo.getCost());
        map.put("thing7", subscribeVo.getProjectName());
        map.put("thing6", subscribeVo.getBillTypeName());
        template.setData(map);


        String requestUrl = SUBSCRIBE_URL + "?access_token=ACCESS_TOKEN";
        requestUrl = requestUrl.replace("ACCESS_TOKEN", getAccessToken(subscribeVo.getFlag()));

        String data = template.toJSON();
        log.debug("data = " + data);
        String result = HttpUtil.post(requestUrl, data);
        Map<String, Object> map1 = GsonUtil.toMap(result);
        if (ObjectUtil.isNotNull(map1)) {
            double errorCode = (double) map1.get("errcode");
            String errorMessage = (String) map1.get("errmsg");
            if (errorCode == 0) {
                return AjaxResult.success();
            } else {
                log.debug("订阅消息发送失败:" + errorCode + "," + errorMessage);
                return AjaxResult.error();
            }
        }
        return AjaxResult.error();
    }

    @Override
    public String getAccessToken(Integer flag) {
        StringBuilder requestUrl = new StringBuilder(ACCESS_TOKEN_URL.length() + 50);
        requestUrl.append(ACCESS_TOKEN_URL).append("?grant_type=client_credential")
                .append("&appid=").append(flag == 1 ? APP_ID : NEW_APP_ID)
                .append("&secret=").append(flag == 1 ? SECRET_KEY : NEW_SECRET_KEY);

        try {
            URL url = new URL(requestUrl.toString());
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            connection.setRequestProperty("Content-Type", "application/json");
            connection.setRequestProperty("Connection", "Keep-Alive");
            connection.setUseCaches(false);
            connection.setDoInput(true);

            StringBuilder response = new StringBuilder();

            try (BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"))) {
                String line;
                while ((line = in.readLine()) != null) {
                    response.append(line);
                }
            }

            JSONObject object = JSON.parseObject(response.toString());
            String accessToken = object.getString("access_token");

            return accessToken;
        } catch (IOException e) {
            log.debug("获取订阅消息 accessToken失败 : " + e.getMessage());
            Integer errorCode = Convert.toInt(StatusCode.ERROR_CODE_10001.getErrorCode());
            throw new BizException(errorCode, "获取订阅消息 accessToken失败");
        }

    }

    @Override
    public AjaxResult sendOrder(String orderId) {

        Order order = orderService.selectOrderById(orderId);
        if (ObjectUtil.isNull(order)) {
            Integer errorCode = Convert.toInt(StatusCode.ERROR_CODE_10001.getErrorCode());
            throw new BizException(errorCode, "订单未找到");
        }


        String userId = order.getReservationId();
        String openId = appUserService.selectOpenIdById(userId);
        if (StrUtil.isBlank(openId)) {
            Integer errorCode = Convert.toInt(StatusCode.ERROR_CODE_10001.getErrorCode());
            throw new BizException(errorCode, "openId有误");
        }

        // 构造模板消息内容
        Map<String, Object> data = new LinkedHashMap<>();
        data.put("thing9", order.getResidenceCommunityName() + order.getBuildingNumName() + "栋" +
                order.getUnitName() + "单元" + order.getRoomNumber());
        data.put("thing2", "房屋订单费用");
        data.put("amount6", order.getPriceAmounts());
        data.put("date3", DateUtil.format(order.getCreateTime(), "yyyy年MM月dd日 HH:mm"));
        data.put("thing4", "订单30分钟后将失效,请尽快支付!");

        Template template = new Template();
        template.setTemplateId(ORDER_STATUS_TEMPLATE_ID);
        template.setToUser(openId);
        template.setPage("pages/order/order-detail?orderId=" + orderId);
        template.setData(data);

        // 发送模板消息
        String requestUrl = SUBSCRIBE_URL + "?access_token=%s";
        requestUrl = String.format(requestUrl, getAccessToken(2));

        String result = null;
        try {
            result = HttpUtil.post(requestUrl, template.toJSON());
        } catch (Exception e) {
            log.error("发送模板消息失败：" + e.getMessage(), e);
        }

        if (StrUtil.isNotBlank(result)) {
            Map<String, Object> resultMap = GsonUtil.toMap(result);
            if (resultMap != null) {
                double errorCode = Convert.toDouble(resultMap.get("errcode"));
                String errorMessage = Convert.toStr(resultMap.get("errmsg"));
                if (errorCode == 0) {
                    return AjaxResult.success();
                } else {
                    log.debug("订阅消息发送失败:" + errorCode + "," + errorMessage);
                }
            }
        }
        return AjaxResult.error();
    }

    @Override
    public AjaxResult sendHouseState(String orderId) {
        Order order = orderService.selectOrderById(orderId);
        if (ObjectUtil.isNull(order)) {
            Integer errorCode = Convert.toInt(StatusCode.ERROR_CODE_10001.getErrorCode());
            return AjaxResult.error(errorCode, "订单未找到");
        }


        String userId = order.getReservationId();
        String openId = appUserService.selectOpenIdById(userId);
        if (StrUtil.isBlank(openId)) {
            Integer errorCode = Convert.toInt(StatusCode.ERROR_CODE_10001.getErrorCode());
            return AjaxResult.error(errorCode, "订单未找到");
        }

        // 构造模板消息内容
        Map<String, Object> data = new LinkedHashMap<>();
        data.put("thing1", order.getResidenceCommunityName() + order.getBuildingNumName() + "栋" +
                order.getUnitName() + "单元" + order.getRoomNumber());
        data.put("phrase3", "已退租");
        data.put("date2", DateUtil.format(DateUtil.date(), "yyyy年MM月dd日 HH:mm"));
        data.put("thing5", "房屋已退租,请及时上传验房图片!");

        Template template = new Template();
        template.setTemplateId(HOUSE_STATE_TEMPLATE_ID);
        template.setToUser(openId);
        template.setPage("/pages/navigation-page/manager/houseInspection?orderId=" + orderId + "&" +
                "houseId=" + order.getHouseId() + "&" + "inspectionStatus=2");
        template.setData(data);

        // 发送模板消息
        String requestUrl = SUBSCRIBE_URL + "?access_token=%s";
        requestUrl = String.format(requestUrl, getAccessToken(2));

        String result = null;
        try {
            result = HttpUtil.post(requestUrl, template.toJSON());
        } catch (Exception e) {
            log.error("发送模板消息失败：" + e.getMessage(), e);
        }

        if (StrUtil.isNotBlank(result)) {
            Map<String, Object> resultMap = GsonUtil.toMap(result);
            if (resultMap != null) {
                double errorCode = Convert.toDouble(resultMap.get("errcode"));
                String errorMessage = Convert.toStr(resultMap.get("errmsg"));
                if (errorCode == 0) {
                    return AjaxResult.success();
                } else {
                    log.debug("订阅消息发送失败:" + errorCode + "," + errorMessage);
                    return AjaxResult.error("订阅消息发送失败:" + errorCode + "," + errorMessage);
                }
            }
        }
        return AjaxResult.error();
    }

    /**
     * 发送公众号账单订阅消息
     * @param subscribeVo
     * @return
     */
    @Override
    public  AjaxResult sendBillMsg(SubscribeVo subscribeVo) {

        // 卡片详情跳转页，设置此值，当点击消息时会打开指定的页面
        String detailUrl = "https://ronghui-h5.runting2020.com/pages/componentsA/payCost/allbill";

        SimpleDateFormat sdf = new SimpleDateFormat();
        sdf.applyPattern("yyyy-MM-dd HH:mm");
        String timeNow = sdf.format(subscribeVo.getBillStartTime());

        WxMpInMemoryConfigStorage wxStorage = new WxMpInMemoryConfigStorage();
        wxStorage.setAppId(officialAccountAppId);
        wxStorage.setSecret(officialAccountSecret);

        WxMpService wxMpService = new WxMpServiceImpl();
        wxMpService.setWxMpConfigStorage(wxStorage);

        // 房号
        // {{thing12.DATA}}
        // 总金额
        // {{amount3.DATA}}
        // 账单类型
        // {{thing14.DATA}}
        // 计费月份
        // {{time8.DATA}}
        // 此处的 key/value 需和模板消息对应
        List<WxMpTemplateData> wxMpTemplateDataList = Arrays.asList(
                new WxMpTemplateData("thing12", subscribeVo.getProjectName()),
                new WxMpTemplateData("thing14", subscribeVo.getBillTypeName()),
                new WxMpTemplateData("amount3", Double.toString(subscribeVo.getCost())),
                new WxMpTemplateData("time8", timeNow)
        );

        WxMpTemplateMessage templateMessage = WxMpTemplateMessage.builder()
                .toUser(subscribeVo.getOpenId())
                .templateId(RP_BILL_MSG_TEMPLATEID)
                .data(wxMpTemplateDataList)
                .url(detailUrl)
                .build();

        try {
            wxMpService.getTemplateMsgService().sendTemplateMsg(templateMessage);
        } catch (Exception e) {
            System.out.println("推送失败：" + e.getMessage());
        }
        return AjaxResult.success();

    }

    /**
     * 发送公众号余额扣减消息
     * @param subscribeVo
     * @return
     */
    @Override
    public  AjaxResult sendDeductionBalanceMsg(SubscribeVo subscribeVo) {

        // 卡片详情跳转页，设置此值，当点击消息时会打开指定的页面
        String detailUrl = "https://ronghui-h5.runting2020.com/pages/componentsA/payCost/allbill";

        WxMpInMemoryConfigStorage wxStorage = new WxMpInMemoryConfigStorage();
        wxStorage.setAppId(officialAccountAppId);
        wxStorage.setSecret(officialAccountSecret);

        WxMpService wxMpService = new WxMpServiceImpl();
        wxMpService.setWxMpConfigStorage(wxStorage);

        // 操作类型
        // {{const2.DATA}}
        // 金额
        // {{amount3.DATA}}
        // 账户余额
        // {{amount4.DATA}}
        // 此处的 key/value 需和模板消息对应
        List<WxMpTemplateData> wxMpTemplateDataList = Arrays.asList(
                new WxMpTemplateData("const2", subscribeVo.getBillTypeName()),
                new WxMpTemplateData("amount3", Double.toString(subscribeVo.getCost())),
                new WxMpTemplateData("amount4", subscribeVo.getBalanceFee())
        );

        WxMpTemplateMessage templateMessage = WxMpTemplateMessage.builder()
                .toUser(subscribeVo.getOpenId())
                .templateId(RP_DEDUCTION_BALANCE_MSG_TEMPLATEID)
                .data(wxMpTemplateDataList)
                .url(detailUrl)
                .build();

        try {
            wxMpService.getTemplateMsgService().sendTemplateMsg(templateMessage);
        } catch (Exception e) {
            System.out.println("推送失败：" + e.getMessage());
        }
        return AjaxResult.success();

    }
}
